#!/usr/bin/env python

from os3.dbm.dbmanager import DBManager
from random import randint

import sys
from hashlib import md5

def cached ( fn ):
	def wrapped ( self, * args, ** kwargs ):
		if kwargs.get ( 'cache', False ):
			time = kwargs.get ( 'cache_time', 600 )
			mem_key = md5 ( str ( args + ( '#', ) + tuple ( sorted ( kwargs.items () ) ) ) ).hexdigest ()
			sys.stderr.write ( 'MEMCACHED - KEY: %s\n' % mem_key )

			result = self.memc.get ( mem_key )
			sys.stderr.write ( "TYPE=%s\n" % type ( result ) )

			if result is None:
				sys.stderr.write ( 'MEMCACHED - KEY NOT FOUND\n' )
				del kwargs [ 'cache' ]
				if 'cache_time' in kwargs: del kwargs [ 'cache_time' ]

				result = fn ( self, * args, ** kwargs )
				sys.stderr.write ( "RESULT=%s\n" % result )
				self.memc.set ( mem_key, result, time )
		else:
			result = fn ( self, * args, ** kwargs )

		return result

	return wrapped

class DBM ( object ):
	DBM_TYPE_MYSQL      = DBManager.DBM_TYPE_MYSQL
        DBM_TYPE_ORACLE     = DBManager.DBM_TYPE_ORACLE
        DBM_TYPE_POSTGRESQL = DBManager.DBM_TYPE_POSTGRESQL
        DBM_TYPE_SQLSERVER  = DBManager.DBM_TYPE_SQLSERVER
        DBM_TYPE_FULCRUM    = DBManager.DBM_TYPE_FULCRUM
        DBM_TYPE_SQLITE     = DBManager.DBM_TYPE_SQLITE
        DBM_TYPE_ADODB      = DBManager.DBM_TYPE_ADODB

	def __init__ ( self, liwe, db_type ):
		self.liwe = liwe
		self.memc = liwe.memc
		self._read_dbms = []
		self._write_dbms = []
		self._all_dbs = []

		self.db_type = DBManager.resolve_type ( db_type )

	def multi_connect ( self, db_defs, prefix = '' ):
		for db in db_defs:
			in_read = False
			in_write = False

			if not 'kind' in db: 
				db [ 'kind' ] = self.db_type
			else:
				db [ 'kind' ] = DBManager.resolve_type ( db [ 'kind' ] )

			if 'read' in db: in_read = bool ( int ( db [ 'read' ] ) )
			if 'write' in db: in_write = bool ( int ( db [ 'read' ] ) )

			new_db = DBManager ( db [ 'kind' ] )

			db [ 'db' ] = db [ 'name' ]
			db [ 'passwd' ] = db [ 'password' ]

			for k in [ 'kind', 'read', 'write', 'name', 'password' ]: 
				if k in db: del db [ k ]

			new_db.connect ( ** db )
			new_db.set_prefix ( prefix )

			if in_read:  self._read_dbms.append ( new_db )
			if in_write: self._write_dbms.append ( new_db )

			self._all_dbs.append ( new_db )

	def close ( self ):
		for db in self._all_dbs: db.close ()

	def select ( self, * args, ** kwargs ):
		return self._select_db_for_read ().select ( * args, ** kwargs )

	def execute ( self, * args, ** kwargs ):
		return self._select_db_for_read ().execute ( * args, ** kwargs )

	def count ( self, * args, ** kwargs ):
		return self._select_db_for_read ().count ( * args, ** kwargs )

	@cached
	def single_row ( self, * args, ** kwargs ):
		return self._select_db_for_read ().single_row ( * args, ** kwargs )

	@cached
	def all_rows ( self, * args, ** kwargs ):
		return self._select_db_for_read ().all_rows ( * args, ** kwargs )

	def insert ( self, * args, ** kwargs ):
		for db in self._write_dbms:
			res = db.insert ( * args, ** kwargs )
		return res

	def replace ( self, * args, ** kwargs ):
		for db in self._write_dbms:
			res = db.replace ( * args, ** kwargs )
		return res

	def insert_id ( self, * args, ** kwargs ):
		return self._write_dbms [ 0 ].insert_id ( * args, ** kwargs )

	def update ( self, * args, ** kwargs ):
		for db in self._write_dbms:
			res = db.update ( * args, ** kwargs )
		return res

	def delete ( self, * args, ** kwargs ):
		for db in self._write_dbms:
			res = db.delete ( * args, ** kwargs )
		return res

	def _select_db_for_read ( self ):
		return self._read_dbms [ randint ( 0, len ( self._read_dbms ) -1 ) ] 

if __name__ == '__main__':
	d = DBM ( DBM.DBM_TYPE_MYSQL )
